﻿using System;
using System.Drawing;
using System.IO;
using System.Web.Mvc;
using AwesomeSlider.Extensions;
using AwesomeSlider.Models;
using AwesomeSlider.Services;
using AwesomeSlider.ViewModels;
using Orchard;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.Core.Contents.Controllers;
using Orchard.Core.Routable.Models;
using Orchard.Core.Routable.Services;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.UI.Admin;
using Orchard.UI.Notify;

namespace AwesomeSlider.Controllers
{
    [ValidateInput(false), Admin]
    public class SliderItemAdminController : Controller, IUpdateModel
    {
        private struct UploadResult
        {
            public readonly string _errorMessage;
            public readonly bool _successfully;

            public UploadResult(string errorMessage, bool successfully)
            {
                _errorMessage = errorMessage;
                _successfully = successfully;
            }
        }

        public Localizer T { get; set; }
        public ILogger Logger { get; set; }
        private readonly IOrchardServices _services;

        private readonly IContentManager _contentManager;
        private readonly ISliderService _sliderService;
        private readonly IMediaExtendedService _mediaService;
        private readonly ISliderItemService _sliderItemService;
        dynamic Shape { get; set; }

        public SliderItemAdminController(IOrchardServices services, IShapeFactory shapeFactory, IContentManager contentManager, ISliderService sliderService,
            ISliderItemService sliderItemService, IMediaExtendedService mediaService)
        {
            _services = services;
            Shape = shapeFactory;

            _contentManager = contentManager;
            _sliderService = sliderService;
            _sliderItemService = sliderItemService;
            _mediaService = mediaService;
        }

        bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties)
        {
            return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
        }

        void IUpdateModel.AddModelError(string key, LocalizedString errorMessage)
        {
            ModelState.AddModelError(key, errorMessage.ToString());
        }

        public ActionResult Add(int sliderId)
        {
            if (!_services.Authorizer.Authorize(Permissions.EditSliderItem, T("Not allowed to create slider item")))
                return new HttpUnauthorizedResult();

            var slider = _sliderService.Get(sliderId, VersionOptions.Latest).As<SliderPart>();
            if (slider == null)
                return HttpNotFound();

            // Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
            return View(slider);
        }

        [HttpPost, ActionName("Add")]
        [FormValueRequired("action")]
        public ActionResult AddPOST(int sliderId, SliderItemViewModel[] sliderItems, string action)
        {
            if (!_services.Authorizer.Authorize(Permissions.EditSliderItem, T("Couldn't create slider item")))
                return new HttpUnauthorizedResult();

            var slider = _sliderService.Get(sliderId, VersionOptions.Latest).As<SliderPart>();
            if (slider == null)
                return HttpNotFound();

            foreach (var sliderItemViewModel in sliderItems)
            {
                var sliderItem = _sliderItemService.Get(sliderItemViewModel.Id);
                if (action == "Save")
                {
                    var routePart = sliderItem.As<RoutePart>();
                    routePart.Title = sliderItemViewModel.Name;
                    routePart.Slug = sliderItem.As<IRoutableAspect>().GetEffectiveSlug();
                    var slidemItemPart = sliderItem.As<SliderItemPart>();
                    slidemItemPart.Description = sliderItemViewModel.Description;
                    _services.ContentManager.Publish(sliderItem);
                }
                else //Cancel
                {
                    Remove(sliderItem.As<SliderItemPart>(), true, false);
                }
            }

            return Redirect(Url.SliderItem(slider));
        }

        private void Remove(SliderItemPart sliderItem, bool removeFile, bool showNotify = true)
        {
            _sliderItemService.Delete(sliderItem);
            if (removeFile)
            {
                try
                {
                    _mediaService.DeleteFile(sliderItem.FullName, sliderItem.Path);
                    if (showNotify)
                    {
                        _services.Notifier.Information(T(string.Format("File {0} was successfully deleted from media.", sliderItem.FullPath)));
                    }
                }
                catch (Exception)
                {
                    if (showNotify)
                    {
                        _services.Notifier.Error(T(string.Format("Cannot delete file {0} from media. Please remove it manually.", sliderItem.FullPath)));
                    }
                }
            }
        }

        [HttpPost]
        public ActionResult UploadFile(int sliderId)
        {
            if (!_services.Authorizer.Authorize(Permissions.EditSliderItem, T("Couldn't slider item")))
                return new HttpUnauthorizedResult();

            var album = _sliderService.Get(sliderId, VersionOptions.Latest).As<SliderPart>();
            if (album == null)
                return HttpNotFound();

            var sliderItem = _sliderItemService.Create(album);
            _services.ContentManager.Create(sliderItem, VersionOptions.Draft);

            var result = UploadFile(sliderItem);

            if (result._successfully)
            {
                return Json(new
                {
                    successfully = true,
                    id = sliderItem.Id,
                    thumb = Url.Thumb(sliderItem.Id, 90, 90),
                    width = 90,
                    height = 90,
                    name = sliderItem.Name,
                }, "text/x-json", System.Text.Encoding.UTF8);
            }
            else
            {
                _sliderItemService.Delete(sliderItem);
                return Json(new
                {
                    successfully = false,
                    errorMessage = result._errorMessage,
                }, "text/x-json", System.Text.Encoding.UTF8);
            }

        }

        private UploadResult UploadFile(SliderItemPart part)
        {
            var postedFile = Request.Files["file"];
            if (postedFile == null || postedFile.ContentLength == 0)
            {
                return new UploadResult(T("File is empty").ToString(), false);
            }

            if (!_mediaService.IsImage(postedFile))
            {
                return new UploadResult(T("Uploaded file is not a image.").ToString(), false);
            }

            string mediaFolder = part.SliderPart.Name;
            if (string.IsNullOrWhiteSpace(mediaFolder))
            {
                return new UploadResult(T("Slider part name is empty").ToString(), false);
            }

            try
            {
                // try to create the folder before uploading a file into it
                _mediaService.CreateFolder(null, mediaFolder);
            }
            catch (Exception)
            {
                // the folder can't be created because it already exists, continue
            }

            var fileName = _mediaService.GetUniqueFilename(mediaFolder, postedFile.FileName);
            part.FileExtension = Path.GetExtension(fileName);
            part.FileName = Path.GetFileNameWithoutExtension(fileName);
            var routePart = part.As<RoutePart>();
            routePart.Title = Path.GetFileNameWithoutExtension(postedFile.FileName);
            routePart.Slug = part.As<IRoutableAspect>().GetEffectiveSlug();

            try
            {
                    Image originalImage = Image.FromStream(postedFile.InputStream);
                    var size = new Size { Height = 280, Width = 280 };
                    Image img = originalImage.ResizeImage(size);
                    _mediaService.UploadMediaFile(mediaFolder, part.FullName, img.ToByteArray(), false);
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Upload image failed");
                return new UploadResult(T("Upload image failed").ToString(), false);
            }

            return new UploadResult(string.Empty, true);
        }



        public ActionResult Edit(int sliderItemId)
        {
            var sliderItem = _sliderItemService.Get(sliderItemId, VersionOptions.Latest);
            if (sliderItem == null)
                return HttpNotFound();

            if (!_services.Authorizer.Authorize(Permissions.EditSliderItem, sliderItem.As<SliderItemPart>().SliderPart, T("Couldn't edit slider item")))
                return new HttpUnauthorizedResult();

            dynamic model = _services.ContentManager.BuildEditor(sliderItem);
            // Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
            return View((object)model);
        }

        [HttpPost, ActionName("Edit")]
        public ActionResult EditPOST(FormCollection input, int sliderItemId)
        {
            var viewModel = new SliderItemViewModel();
            var sliderItem = _sliderItemService.Get(sliderItemId, VersionOptions.Latest);
            if (sliderItem == null)
                return HttpNotFound();
            try
            {
                UpdateModel(viewModel);

                _services.ContentManager.UpdateEditor(sliderItem, this);

                _contentManager.Publish(sliderItem);

                if (!_services.Authorizer.Authorize(Permissions.EditSliderItem, sliderItem.As<SliderItemPart>().SliderPart, T("Couldn't edit slider item")))
                    return new HttpUnauthorizedResult();
            

                _sliderItemService.UpdateDescription(sliderItemId, viewModel.Description);


                _services.Notifier.Information(T("SliderItem updated"));
                return Redirect(Url.SliderItem(sliderItem.As<SliderItemPart>().SliderPart));
            }
            catch (Exception exception)
            {
                _services.Notifier.Information(T("SliderItem not updated"));

                return Redirect(Url.SliderItem(sliderItem.As<SliderItemPart>().SliderPart));
            }
        }


        [HttpPost]
        public ActionResult Remove(int sliderItemId, bool deleteFile)
        {
            if (!_services.Authorizer.Authorize(Permissions.ManageSliders, T("Couldn't delete slider item")))
                return new HttpUnauthorizedResult();

            //bool removeFile = Request.Form["deleteFile"].ToBool() ?? false;
            var contentItem = _sliderItemService.Get(sliderItemId, VersionOptions.Latest);

            if (contentItem == null)
                return HttpNotFound();
            var sliderItem = contentItem.As<SliderItemPart>();
            var slider = sliderItem.SliderPart;
            int sliderId = slider.Id;

            RemoveSliderItem(sliderItem, deleteFile);

            _services.Notifier.Information(T("Slider Item was successfully deleted"));
            return Request.IsAjaxRequest()
                ? (ActionResult)JavaScript(string.Format("window.location='{0}';", Url.SliderItem(sliderId)))
                : Redirect(Url.SliderItem(slider));
        }

        private void RemoveSliderItem(SliderItemPart slider, bool removeFile, bool showNotify = true)
        {
            _sliderItemService.Delete(slider);
            if (removeFile)
            {
                try
                {
                    _mediaService.DeleteFile(slider.Path, slider.FullName);
                    if (showNotify)
                    {
                        _services.Notifier.Information(T(string.Format("File {0} was successfully deleted from media.", slider.FullPath)));
                    }
                }
                catch (Exception e)
                {
                    if (showNotify)
                    {
                        _services.Notifier.Error(T(string.Format("Cannot delete file {0} from media. Please remove it manually.", slider.FullPath)));
                    }
                }
            }
        }

    }
}